package com.blue.Impl.workflow;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.blue.common.constant.CommonConstant;
import com.blue.common.entity.LoginUserInfo;
import com.blue.common.exception.CustomException;
import com.blue.common.utils.ConvertUtils;
import com.blue.common.utils.SpringContextUtils;
import com.blue.common.utils.ThreadLocalUtils;
import com.blue.dto.workflow.*;
import com.blue.po.author.UserPO;
import com.blue.po.author.UserRolePO;
import com.blue.po.workflow.*;
import com.blue.service.author.IUserService;
import com.blue.service.system.IMessageService;
import com.blue.service.workflow.*;
import com.blue.vo.author.UserVO;
import com.blue.vo.workflow.BusinessFieldVO;
import com.blue.vo.workflow.WorkFlowInitVO;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class WorkflowServiceImpl implements IWorkflowService {
    @Autowired
    private INodeService nodeService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IDefinitionService definitionService;
    @Autowired
    private IInstanceService instanceService;
    @Autowired
    private ITaskInstanceService taskInstanceService;
    @Autowired
    private IBusinessDataService businessDataService;
    @Autowired
    private IBusinessFieldService businessFieldService;
    @Autowired
    private IConditionService conditionService;
    @Autowired
    private INodeConditionService nodeConditionService;
    @Autowired
    private IMessageService messageService;
    @Autowired
    private ITaskCcService taskCcService;


    @Override
    public WorkFlowInitVO init(WorkFlowInitDTO requestDTO) {
        WorkFlowInitVO workFlowInitVO = new WorkFlowInitVO();
        LoginUserInfo loginUserInfo = ThreadLocalUtils.getLoginUserInfo();
        //definitionId不为空表示开始节点,否则为其他节点
        String definitionId = requestDTO.getDefinitionId();
        Object data;
        NodePO currentNode;
        if (StringUtils.isNotBlank(definitionId)) {
            workFlowInitVO.setDefinitionId(definitionId);
            //获取该流程定义的开始节点信息
            currentNode = nodeService.getOne(new LambdaQueryWrapper<NodePO>()
                    .eq(NodePO::getDefinitionId, definitionId)
                    .eq(NodePO::getNodeType, CommonConstant.START_NODE));
            if (currentNode == null) {
                throw new CustomException("流程开始节点不存在！");
            }
            //提交审批人校验
            approverCheck(currentNode, loginUserInfo);
            workFlowInitVO.setCurrentNodeId(currentNode.getId());
            workFlowInitVO.setCurrentNodeType(currentNode.getNodeType());
            //业务数据
            data = requestDTO.getData();
        } else {
            String instanceId = requestDTO.getInstanceId();
            if (StringUtils.isBlank(instanceId)) {
                throw new CustomException("流程实例ID不能为空！");
            }
            workFlowInitVO.setInstanceId(instanceId);
            InstancePO instancePO = instanceService.getOne(new LambdaQueryWrapper<InstancePO>()
                    .select(InstancePO::getCurrentNodeId, InstancePO::getDefinitionId)
                    .eq(InstancePO::getId, instanceId));
            workFlowInitVO.setCurrentNodeId(instancePO.getCurrentNodeId());
            workFlowInitVO.setDefinitionId(instancePO.getDefinitionId());
            currentNode = nodeService.getById(instancePO.getCurrentNodeId());
            if (currentNode == null) {
                throw new CustomException("流程当前节点不存在！");
            }
            //提交审批人校验(转办/加签任务不需要校验)
            TaskInstancePO taskInstancePO = taskInstanceService.getOne(new LambdaQueryWrapper<TaskInstancePO>()
                    .select(TaskInstancePO::getRelateTaskId)
                    .eq(TaskInstancePO::getInstanceId, instanceId)
                    .eq(TaskInstancePO::getCurrentNodeId, currentNode.getId())
                    .eq(TaskInstancePO::getStatus, CommonConstant.PENDING)
                    .eq(TaskInstancePO::getAssigneeId, loginUserInfo.getUserId()));
            if (taskInstancePO != null && StringUtils.isBlank(taskInstancePO.getRelateTaskId())) {
                approverCheck(currentNode, loginUserInfo);
            }
            workFlowInitVO.setCurrentNodeType(currentNode.getNodeType());
            if (CommonConstant.END_NODE.equals(currentNode.getNodeType())) {
                return workFlowInitVO;
            }
            //业务数据
            data = businessDataService.getData(instanceId);
        }
        //查询所有节点
        List<NodePO> allNode = nodeService.list(new LambdaQueryWrapper<NodePO>()
                .eq(NodePO::getDefinitionId, currentNode.getDefinitionId()));
        //获取下个节点
        NodePO nextNode = getNextNode(allNode, currentNode, data);
        if (nextNode == null) {
            throw new CustomException("下级流程节点不存在！");
        }
        workFlowInitVO.setNextNodeId(nextNode.getId());
        workFlowInitVO.setApprovalType(currentNode.getApprovalType());
        //获取处理人
        List<UserVO> assignees = getAssignees(nextNode);
        workFlowInitVO.setAssignees(assignees);
        return workFlowInitVO;
    }

    /**
     * 提交审批人校验
     *
     * @param nodePO
     */
    private void approverCheck(NodePO nodePO, LoginUserInfo loginUserInfo) {
        String assigneeType = nodePO.getAssigneeType();
        String assigneeValue = nodePO.getAssigneeValue();
        if (StringUtils.isBlank(assigneeType) || StringUtils.isBlank(assigneeValue)) {
            return;
        }
        if (CommonConstant.USER.equals(assigneeType) && !assigneeValue.equals(loginUserInfo.getUserId())) {
            throw new CustomException("提交审批人与当前节点不匹配！");
        } else if (CommonConstant.ROLE_DEPT.equals(assigneeType)) {
            //如果是部门加角色需要处理assigneeValue的值
            String[] arr = assigneeValue.split(",");
            if (arr.length != 2) {
                throw new CustomException("流程节点处理人值配置异常！");
            }
            String roleId = arr[0];
            String deptId = arr[1];
            if (!roleId.equals(loginUserInfo.getRoleId()) || !deptId.equals(loginUserInfo.getDeptId())) {
                throw new CustomException("提交审批人与当前节点不匹配！");
            }
        } else if (CommonConstant.ROLE.equals(assigneeType) && !assigneeValue.equals(loginUserInfo.getRoleId())) {
            throw new CustomException("提交审批人与当前节点不匹配！");
        } else if (CommonConstant.DEPT.equals(assigneeType) && !assigneeValue.equals(loginUserInfo.getDeptId())) {
            throw new CustomException("提交审批人与当前节点不匹配！");
        }

    }


    /**
     * 获取下级节点
     * 下级节点存在几种情况
     * 一、下级节点只有一个
     * 1.为审批节点--直接作为下级节点
     * 2.为网关节点--网关下级节点必为条件节点，再向下查找审批节点
     * 二、下级节点不存在
     * 1.查询outNodeId的下级节点
     */
    private NodePO getNextNode(List<NodePO> allNode, NodePO currentNode, Object data) {
        NodePO nextNode = allNode.stream()
                .filter(item -> currentNode.getId().equals(item.getParentNodeId())
                        && !CommonConstant.CONDITION_NODE.equals(item.getNodeType()))
                .findFirst()
                .orElse(null);
        if (nextNode == null) {
            NodePO outNodePO = allNode.stream()
                    .filter(item -> currentNode.getOutNodeId().equals(item.getId()))
                    .findFirst()
                    .orElse(null);
            if (outNodePO == null) {
                throw new CustomException("当前节点最外层网关节点不存在！");
            }
            NodePO nodePO = allNode.stream()
                    .filter(item -> outNodePO.getId().equals(item.getParentNodeId())
                            && !CommonConstant.CONDITION_NODE.equals(item.getNodeType()))
                    .findFirst().orElse(null);
            if (nodePO == null) {
                throw new CustomException("最外层非条件下级节点不存在！");
            }
            if (CommonConstant.APPROVE_NODE.equals(nodePO.getNodeType())) {
                return nodePO;
            }
            return getNextNode(allNode, outNodePO, data);
        } else {
            if (CommonConstant.APPROVE_NODE.equals(nextNode.getNodeType()) || CommonConstant.END_NODE.equals(nextNode.getNodeType())) {
                return nextNode;
            } else if (CommonConstant.GATEWAY_NODE.equals(nextNode.getNodeType())) {
                List<NodePO> conditionNodes = allNode.stream()
                        .filter(item -> nextNode.getId().equals(item.getParentNodeId())
                                && CommonConstant.CONDITION_NODE.equals(item.getNodeType()))
                        .toList();
                NodePO conditionNode = getConditionNode(conditionNodes, data);
                if (conditionNode == null) {
                    throw new CustomException("没有满足条件的节点信息！");
                }
                return allNode.stream()
                        .filter(item -> conditionNode.getId().equals(item.getParentNodeId()))
                        .findFirst()
                        .orElse(null);
            }
            throw new CustomException("下级节点类型异常！");
        }
    }

    /**
     * 获取满足条件节点
     *
     * @param conditionNodes
     * @param data
     * @return
     */
    private NodePO getConditionNode(List<NodePO> conditionNodes, Object data) {
        for (NodePO conditionNode : conditionNodes) {
            //查询node条件信息
            List<NodeConditionPO> nodeConditionPOS = nodeConditionService.list(new LambdaQueryWrapper<NodeConditionPO>()
                    .eq(NodeConditionPO::getNodeId, conditionNode.getId()));
            //判断条件
            boolean flag = false;
            for (NodeConditionPO nodeConditionPO : nodeConditionPOS) {
                ConditionPO conditionPO = conditionService.getById(nodeConditionPO.getConditionId());
                //数据源支持业务数据和当前处理人信息
                Map<String, Object> map = new HashMap<>();
                if (CommonConstant.DATA.equals(conditionPO.getFieldSource())) {
                    map = ConvertUtils.convert(Map.class, data);

                } else if (CommonConstant.APPROVER.equals(conditionPO.getFieldSource())) {
                    String userId = ThreadLocalUtils.getLoginUserInfo().getUserId();
                    UserPO userPO = userService.getById(userId);
                    map = ConvertUtils.convert(Map.class, userPO);
                }
                //条件比较值
                Object value = map.get(conditionPO.getFieldEnNm());
                if (value == null) {
                    throw new CustomException("条件值信息不存在！");
                }
                flag = compare(nodeConditionPO, conditionPO.getFieldValueType(), value);
            }
            if (flag) {
                return conditionNode;
            }
        }
        return null;
    }


    /**
     * 比较节点条件值
     *
     * @param nodeConditionPO
     * @param fieldType
     * @param value
     * @return
     */
    private boolean compare(NodeConditionPO nodeConditionPO, String fieldType, Object value) {
        if (!(value instanceof String strValue)) {
            throw new CustomException("条件值与配置值类型不匹配！");
        }
        if (CommonConstant.STRING.equals(fieldType)) {
            if (!"=".equals(nodeConditionPO.getComparison()) && !"!=".equals(nodeConditionPO.getComparison())) {
                throw new CustomException("条件值配置字符串类型比较符只能是等于和不等于！");
            }
            return strValue.equals(nodeConditionPO.getConditionValue());
        } else if (CommonConstant.NUMBER.equals(fieldType)) {
            if (!strValue.matches("-?\\d+(\\.\\d+)?")) {
                throw new CustomException("条件值与配置值类型不匹配！");
            }
            BigDecimal numValue = new BigDecimal(strValue);
            BigDecimal condValue = new BigDecimal(nodeConditionPO.getConditionValue());
            int i = numValue.compareTo(condValue);
            switch (nodeConditionPO.getComparison()) {
                case "等于":
                    if (i == 0) {
                        return true;
                    }
                    break;
                case "大于":
                    if (i > 0) {
                        return true;
                    }
                    break;
                case "小于":
                    if (i < 0) {
                        return true;
                    }
                    break;
                case "小于等于":
                    if (i < 0 || i == 0) {
                        return true;
                    }
                    break;
                case "大于等于":
                    if (i > 0 || i == 0) {
                        return true;
                    }
                    break;
                case "不等于":
                    if (i != 0) {
                        return true;
                    }
                    break;
            }
        }
        return false;
    }

    /**
     * 获取处理人
     *
     * @param nodePO
     * @return
     */
    private List<UserVO> getAssignees(NodePO nodePO) {
        String assigneeType = nodePO.getAssigneeType();
        String assigneeValue = nodePO.getAssigneeValue();
        if (StringUtils.isBlank(assigneeType)) {
            throw new CustomException("流程节点处理人配置异常！");
        }
        MPJLambdaWrapper<UserPO> mpjLambdaWrapper = JoinWrappers.lambda(UserPO.class)
                .select(UserPO::getUserId, UserPO::getUsername)
                .eq(UserPO::getStatus, CommonConstant.NORMAL);
        //根据处理人类型获取处理人信息
        if (CommonConstant.USER.equals(assigneeType)) {
            if (StringUtils.isBlank(assigneeValue)) {
                throw new CustomException("流程节点处理人配置异常！");
            }
            List<String> userIds = Arrays.asList(assigneeValue.split(","));
            mpjLambdaWrapper.in(UserPO::getUserId, userIds);
        } else if (CommonConstant.ROLE_DEPT.equals(assigneeType)) {
            //如果是部门加角色需要处理assigneeValue的值
            if (StringUtils.isBlank(assigneeValue)) {
                throw new CustomException("流程节点处理人配置异常！");
            }
            String[] arr = assigneeValue.split(",");
            if (arr.length != 2) {
                throw new CustomException("流程节点处理人值配置异常！");
            }
            String roleId = arr[0];
            String deptId = arr[1];
            mpjLambdaWrapper.leftJoin(UserRolePO.class, UserRolePO::getUserId, UserPO::getUserId)
                    .eq(UserPO::getDeptId, deptId)
                    .eq(UserRolePO::getRoleId, roleId);
        } else if (CommonConstant.ROLE.equals(assigneeType)) {
            if (StringUtils.isBlank(assigneeValue)) {
                throw new CustomException("流程节点处理人配置异常！");
            }
            mpjLambdaWrapper.leftJoin(UserRolePO.class, UserRolePO::getUserId, UserPO::getUserId)
                    .eq(UserRolePO::getRoleId, assigneeValue);
        } else if (CommonConstant.DEPT.equals(assigneeType)) {
            if (StringUtils.isBlank(assigneeValue)) {
                throw new CustomException("流程节点处理人配置异常！");
            }
            mpjLambdaWrapper.eq(UserPO::getDeptId, assigneeValue);
        } else if (CommonConstant.LEADER.equals(assigneeType)) {
            mpjLambdaWrapper.eq(UserPO::getUserId, ThreadLocalUtils.getLoginUserInfo().getLeaderId());
        } else if (CommonConstant.SELF.equals(assigneeType)) {
            mpjLambdaWrapper.eq(UserPO::getUserId, ThreadLocalUtils.getLoginUserInfo().getUserId());
        }
        List<UserPO> userPOS = userService.list(mpjLambdaWrapper);
        return ConvertUtils.convertList(UserVO.class, userPOS);
    }


    @Override
    @Transactional
    public void start(WorkflowStartDTO requestDTO) {
        DefinitionPO definitionPO = definitionService.getOne(new LambdaQueryWrapper<DefinitionPO>()
                .select(DefinitionPO::getDefinitionNm, DefinitionPO::getBusinessClass, DefinitionPO::getStatus)
                .eq(DefinitionPO::getId, requestDTO.getDefinitionId()));
        if (CommonConstant.DISABLE.equals(definitionPO.getStatus())) {
            throw new CustomException("流程未开启！");
        }
        NodePO nextNodePO = nodeService.getOne(new LambdaQueryWrapper<NodePO>()
                .select(NodePO::getMultiType)
                .eq(NodePO::getId, requestDTO.getNextNodeId())
                .eq(NodePO::getDefinitionId, requestDTO.getDefinitionId()));
        if (nextNodePO == null) {
            throw new CustomException("下级流程节点不存在！");
        }
        String instanceId = requestDTO.getInstanceId();
        BigDecimal taskSort = BigDecimal.ONE;
        //实例为空表示启动流程不为空表示重启流程
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        if (StringUtils.isBlank(instanceId)) {
            //创建流程实例
            InstancePO instancePO = new InstancePO();
            instancePO.setDefinitionId(requestDTO.getDefinitionId());
            instancePO.setStartTime(startTime);
            instancePO.setStatus(CommonConstant.RUNNING);
            instancePO.setInitiatorId(ThreadLocalUtils.getLoginUserInfo().getUserId());
            instancePO.setCurrentNodeId(requestDTO.getNextNodeId());
            instanceService.save(instancePO);
            instanceId = instancePO.getId();
        } else {
            //更新实例状态为运行
            instanceService.update(new LambdaUpdateWrapper<InstancePO>()
                    .set(InstancePO::getStatus, CommonConstant.RUNNING)
                    .set(InstancePO::getCurrentNodeId, requestDTO.getNextNodeId())
                    .set(InstancePO::getEndTime, null)
                    .eq(InstancePO::getId, instanceId));
            //更新该实例的业务数据的是否展示为否
            businessDataService.update(new LambdaUpdateWrapper<BusinessDataPO>()
                    .set(BusinessDataPO::getDisplayFlag, CommonConstant.NO)
                    .eq(BusinessDataPO::getInstanceId, instanceId));
            //查询当前流程实例任务的最大排序数
            List<TaskInstancePO> taskInstancePOS = taskInstanceService.list(new LambdaQueryWrapper<TaskInstancePO>()
                    .select(TaskInstancePO::getSort)
                    .eq(TaskInstancePO::getInstanceId, instanceId));
            taskSort = taskInstancePOS.stream().map(TaskInstancePO::getSort)
                    .max(BigDecimal::compareTo)
                    .orElse(BigDecimal.ONE);
            //创建重新发起任务
            TaskInstancePO taskInstancePO = new TaskInstancePO();
            taskInstancePO.setInstanceId(instanceId);
            taskInstancePO.setStatus(CommonConstant.RESTART);
            String operationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            taskInstancePO.setOperationTime(operationTime);
            taskInstancePO.setAssigneeId(ThreadLocalUtils.getLoginUserInfo().getUserId());
            taskInstancePO.setSort(taskSort.add(BigDecimal.ONE));
            taskInstanceService.save(taskInstancePO);
            taskSort = taskSort.add(BigDecimal.valueOf(2));
        }
        //插入最新的流程业务数据
        BusinessDataPO businessDataPO = new BusinessDataPO();
        businessDataPO.setInstanceId(instanceId);
        businessDataPO.setBusinessData(JSON.toJSONString(requestDTO.getData()));
        businessDataPO.setDisplayFlag(CommonConstant.YES);
        businessDataService.save(businessDataPO);
        //创建流程任务实例
        List<TaskInstancePO> taskInstancePOS = saveTaskInstance(requestDTO.getAssigneeIds(), instanceId, requestDTO.getNextNodeId(),
                null, nextNodePO.getMultiType(), taskSort, CommonConstant.APPROVE_TYPE, null);
        WorkflowProcessHandler processHandler = getProcessHandler(definitionPO.getBusinessClass());
        //发送待办消息
        messageService.sendTodoMessage(instanceId, taskInstancePOS, definitionPO.getDefinitionNm());
        //执行流程过程业务逻辑
        if (processHandler != null) {
            WorkFlowProcessDTO workFlowProcessDTO = new WorkFlowProcessDTO();
            workFlowProcessDTO.setInstanceId(instanceId);
            workFlowProcessDTO.setData(requestDTO.getData());
            processHandler.startProcess(workFlowProcessDTO);
        }
        if (CollectionUtils.isEmpty(requestDTO.getCcToIds())) {
            return;
        }
        //添加抄送信息
        cc(requestDTO.getCcToIds(), instanceId, null, startTime);
        //发送抄送消息
        messageService.sendCcToMessage(requestDTO.getCcToIds(), instanceId, definitionPO.getDefinitionNm());
    }


    @Override
    @Transactional
    public void commit(WorkflowCommitDTO requestDTO) {
        //校验
        InstancePO instancePO = instanceService.getById(requestDTO.getInstanceId());
        if (instancePO == null) {
            throw new CustomException("流程实例不存在！");
        }
        DefinitionPO definitionPO = definitionService.getById(instancePO.getDefinitionId());
        if (CommonConstant.DISABLE.equals(definitionPO.getStatus())) {
            throw new CustomException("流程未开启！");
        }
        if (!CommonConstant.RUNNING.equals(instancePO.getStatus())) {
            throw new CustomException("流程实例非运行状态！");
        }
        TaskInstancePO taskInstancePO = taskInstanceService.getById(requestDTO.getTaskId());
        if (taskInstancePO == null) {
            throw new CustomException("流程任务实例不存在！");
        }
        //校验流程任务实例当前节点与流程实例当前节点是否一致
        if (!instancePO.getCurrentNodeId().equals(taskInstancePO.getCurrentNodeId())) {
            throw new CustomException("流程节点不匹配！");
        }
        //校验当前提交人是否为流程任务实例处理人
        String userId = ThreadLocalUtils.getLoginUserInfo().getUserId();
        if (!taskInstancePO.getAssigneeId().equals(userId)) {
            throw new CustomException("流程任务实例处理人不匹配！");
        }
        //获取业务数据
        Object data = businessDataService.getData(instancePO.getId());
        //获取当前节点信息
        NodePO currentNode = nodeService.getById(taskInstancePO.getCurrentNodeId());
        //校验下个节点是否正确
        NodePO nextNode = new NodePO();
        if (StringUtils.isNotBlank(requestDTO.getNextNodeId())) {
            List<NodePO> allNodes = nodeService.list(new LambdaQueryWrapper<NodePO>()
                    .eq(NodePO::getDefinitionId, instancePO.getDefinitionId()));
            nextNode = getNextNode(allNodes, currentNode, data);
            if (!requestDTO.getNextNodeId().equals(nextNode.getId())) {
                throw new CustomException("下个流程节点ID有误！");
            }
        }
        //根据不同的审批状态执行不同逻辑
        String approvalStatus = requestDTO.getApprovalStatus();
        String operationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //设置审批意见
        taskInstancePO.setRemark(requestDTO.getRemark());
        //审批通过
        if (CommonConstant.APPROVED.equals(approvalStatus)) {
            //保存提交中的业务数据并将该数据设置为展示数据
            if (requestDTO.getData() != null) {
                businessDataService.update(new LambdaUpdateWrapper<BusinessDataPO>()
                        .set(BusinessDataPO::getDisplayFlag, CommonConstant.NO)
                        .eq(BusinessDataPO::getInstanceId, instancePO.getId()));
                BusinessDataPO businessDataPO = new BusinessDataPO();
                businessDataPO.setInstanceId(instancePO.getId());
                businessDataPO.setTaskInstanceId(taskInstancePO.getId());
                businessDataPO.setBusinessData(JSON.toJSONString(requestDTO.getData()));
                businessDataPO.setDisplayFlag(CommonConstant.YES);
                businessDataService.save(businessDataPO);
            }
            //判断当前节点是否为结束节点
            if (CommonConstant.END_NODE.equals(currentNode.getNodeType())) {
                //判断节点审批方式
                if (CommonConstant.OR_SIGN.equals(currentNode.getMultiType())) {
                    endApproved(definitionPO, instancePO, data, operationTime, currentNode.getId(), userId);
                } else if (CommonConstant.COUNTERSIGN.equals(currentNode.getMultiType())) {
                    //会签需判断当前节点的非当前操作人的任务实例是否已全部处理
                    List<String> taskStatus = getTaskStatus(instancePO.getId(), userId, taskInstancePO.getSort(), currentNode.getId());
                    //不包含pending表示该节点的非当前当前操作人的任务实例已全部执行完
                    if (!taskStatus.contains(CommonConstant.PENDING)) {
                        endApproved(definitionPO, instancePO, data, operationTime, currentNode.getId(), userId);
                    }
                }
            } else {
                //判断当前节点是或签还是会签
                if (CommonConstant.OR_SIGN.equals(currentNode.getMultiType())) {
                    approved(requestDTO, definitionPO, data, instancePO, operationTime, currentNode.getId(), userId, nextNode.getMultiType(), taskInstancePO.getSort());
                } else if (CommonConstant.COUNTERSIGN.equals(currentNode.getMultiType())) {
                    //会签需判断当前节点的非当前操作人的实例任务是否已全部处理
                    List<String> taskStatus = getTaskStatus(instancePO.getId(), userId, taskInstancePO.getSort(), currentNode.getId());
                    //不包含pending表示该节点的非当前任务已全部执行完
                    if (!taskStatus.contains(CommonConstant.PENDING)) {
                        approved(requestDTO, definitionPO, data, instancePO, operationTime, currentNode.getId(), userId, nextNode.getMultiType(), taskInstancePO.getSort());
                    }
                }
            }
            //设置流程任务实例状态为approved和操作时间
            taskInstancePO.setStatus(CommonConstant.APPROVED);
            taskInstancePO.setOperationTime(operationTime);
            //拒绝
        } else if (CommonConstant.REJECTED.equals(approvalStatus)) {
            //执行流程过程业务逻辑
            WorkflowProcessHandler processHandler = getProcessHandler(definitionPO.getBusinessClass());
            if (processHandler != null) {
                WorkFlowProcessDTO workFlowProcessDTO = new WorkFlowProcessDTO();
                workFlowProcessDTO.setInstanceId(instancePO.getId());
                workFlowProcessDTO.setData(data);
                processHandler.rejectedProcess(workFlowProcessDTO);
            }
            //作废节点非当前节点任务
            cancelTask(operationTime, instancePO.getId(), currentNode.getId(), userId);
            //设置流程任务实例状态为rejected和操作时间
            taskInstancePO.setStatus(CommonConstant.REJECTED);
            taskInstancePO.setOperationTime(operationTime);
            //更新流程实例
            instancePO.setCurrentNodeId(requestDTO.getNextNodeId());
            instancePO.setEndTime(operationTime);
            instancePO.setStatus(CommonConstant.REJECTED);
            instanceService.updateById(instancePO);
            //发送拒绝消息
            messageService.sendSystemMessage(instancePO.getInitiatorId(), instancePO.getId(), CommonConstant.REJECTED, definitionPO.getDefinitionNm());
            //退回
        } else if (CommonConstant.BACK.equals(approvalStatus)) {
            //执行流程过程业务逻辑
            WorkflowProcessHandler processHandler = getProcessHandler(definitionPO.getBusinessClass());
            if (processHandler != null) {
                WorkFlowProcessDTO workFlowProcessDTO = new WorkFlowProcessDTO();
                workFlowProcessDTO.setInstanceId(instancePO.getId());
                workFlowProcessDTO.setData(data);
                processHandler.backProcess(workFlowProcessDTO);
            }
            //作废节点非当前节点任务
            cancelTask(operationTime, instancePO.getId(), currentNode.getId(), userId);
            //根据当前node节点配置信息退回到相应节点
            if (CommonConstant.BACK_FIRST.equals(currentNode.getBackStrategy()) || StringUtils.isBlank(taskInstancePO.getPreviousNodeId())) {
                //更新流程实例
                instanceService.update(new LambdaUpdateWrapper<InstancePO>()
                        .set(InstancePO::getStatus, CommonConstant.BACK)
                        .set(InstancePO::getEndTime, operationTime)
                        .set(InstancePO::getCurrentNodeId, null)
                        .eq(InstancePO::getId, instancePO.getId()));
                //发送退回消息
                messageService.sendSystemMessage(instancePO.getInitiatorId(), instancePO.getId(), CommonConstant.BACK, definitionPO.getDefinitionNm());
            } else if (CommonConstant.BACK_LAST.equals(currentNode.getBackStrategy())) {
                //给上个节点处理人创建流程任务实例
                List<TaskInstancePO> previousTaskInstances = taskInstanceService.list(new LambdaQueryWrapper<TaskInstancePO>()
                        .eq(TaskInstancePO::getInstanceId, instancePO.getId())
                        .eq(TaskInstancePO::getCurrentNodeId, taskInstancePO.getPreviousNodeId())
                        .eq(TaskInstancePO::getSort, taskInstancePO.getSort().subtract(BigDecimal.ONE)));
                List<TaskInstancePO> taskInstancePOS = new ArrayList<>();
                previousTaskInstances.forEach(item -> {
                    TaskInstancePO taskInstance = new TaskInstancePO();
                    taskInstance.setInstanceId(instancePO.getId());
                    taskInstance.setStatus(CommonConstant.PENDING);
                    taskInstance.setCurrentNodeId(item.getCurrentNodeId());
                    taskInstance.setAssigneeId(item.getAssigneeId());
                    taskInstance.setPreviousNodeId(item.getPreviousNodeId());
                    taskInstance.setSort(taskInstancePO.getSort().add(BigDecimal.ONE));
                    taskInstance.setMultiType(item.getMultiType());
                    taskInstancePOS.add(taskInstance);
                });
                taskInstanceService.saveBatch(taskInstancePOS);
                //更新流程实例
                instancePO.setCurrentNodeId(currentNode.getParentNodeId());
                instanceService.updateById(instancePO);
                //发送待办消息
                messageService.sendTodoMessage(instancePO.getId(), taskInstancePOS, definitionPO.getDefinitionNm());
            }
            //设置流程任务实例为back
            taskInstancePO.setStatus(CommonConstant.BACK);
            taskInstancePO.setOperationTime(operationTime);
        } else if (CommonConstant.TRANSFER.equals(approvalStatus)) {
            //创建转办流程任务实例
            List<TaskInstancePO> taskInstancePOS = saveTaskInstance(requestDTO.getAssigneeIds(), instancePO.getId(), requestDTO.getCurrentNodeId(),
                    taskInstancePO.getPreviousNodeId(), currentNode.getMultiType(), taskInstancePO.getSort(), CommonConstant.TRANSFER_TYPE, taskInstancePO.getId());
            //设置流程任务实例状态为transfer和操作时间
            taskInstancePO.setStatus(CommonConstant.TRANSFER);
            taskInstancePO.setOperationTime(operationTime);
            //发送待办消息
            messageService.sendTodoMessage(instancePO.getId(), taskInstancePOS, definitionPO.getDefinitionNm());
        } else if (CommonConstant.ADD_SIGN.equals(approvalStatus)) {
            //创建转办流程任务实例
            List<TaskInstancePO> taskInstancePOS = saveTaskInstance(requestDTO.getAssigneeIds(), instancePO.getId(), requestDTO.getCurrentNodeId(),
                    taskInstancePO.getPreviousNodeId(), currentNode.getMultiType(), taskInstancePO.getSort(), CommonConstant.ADD_SIGN_TYPE, taskInstancePO.getId());
            //发送待办消息
            messageService.sendTodoMessage(instancePO.getId(), taskInstancePOS, definitionPO.getDefinitionNm());
        } else {
            throw new CustomException("审批状态异常！");
        }
        //更新当前流程任务实例信息
        taskInstanceService.updateById(taskInstancePO);
        if (CollectionUtils.isEmpty(requestDTO.getCcToIds())) {
            return;
        }
        //添加抄送信息
        cc(requestDTO.getCcToIds(), requestDTO.getInstanceId(), requestDTO.getTaskId(), operationTime);
        //发送抄送消息
        messageService.sendCcToMessage(requestDTO.getCcToIds(), requestDTO.getInstanceId(), definitionPO.getDefinitionNm());
    }

    /**
     * 获取当前节点非当前操作人的任务实例状态
     *
     * @param instanceId
     * @param userId
     * @param sort
     * @param currentNodeId
     * @return
     */
    private List<String> getTaskStatus(String instanceId, String userId, BigDecimal sort, String currentNodeId) {
        List<TaskInstancePO> taskInstancePOS = taskInstanceService.list(new LambdaQueryWrapper<TaskInstancePO>()
                .select(TaskInstancePO::getStatus)
                .eq(TaskInstancePO::getInstanceId, instanceId)
                .ne(TaskInstancePO::getAssigneeId, userId)
                .eq(TaskInstancePO::getSort, sort)
                .eq(TaskInstancePO::getCurrentNodeId, currentNodeId));
        List<String> taskStatus = new ArrayList<>();
        if (taskInstancePOS != null) {
            taskStatus = taskInstancePOS.stream().map(TaskInstancePO::getStatus).toList();
        }
        return taskStatus;
    }

    /**
     * 结束节点同意审批
     *
     * @param definitionPO
     * @param instancePO
     * @param data
     * @param operationTime
     * @param currentNodeId
     * @param userId
     */
    private void endApproved(DefinitionPO definitionPO, InstancePO instancePO, Object data,
                             String operationTime, String currentNodeId, String userId) {
        //执行流程过程业务逻辑
        WorkflowProcessHandler processHandler = getProcessHandler(definitionPO.getBusinessClass());
        if (processHandler != null) {
            WorkFlowProcessDTO workFlowProcessDTO = new WorkFlowProcessDTO();
            workFlowProcessDTO.setInstanceId(instancePO.getId());
            workFlowProcessDTO.setData(data);
            processHandler.completedProcess(workFlowProcessDTO);
        }
        //作废节点非当前节点任务
        cancelTask(operationTime, instancePO.getId(), currentNodeId, userId);
        //设置流程实例结束时间和状态为completed
        instancePO.setEndTime(operationTime);
        instancePO.setStatus(CommonConstant.COMPLETED);
        instanceService.updateById(instancePO);
        //发送审批完成消息
        messageService.sendSystemMessage(instancePO.getInitiatorId(), instancePO.getId(), CommonConstant.COMPLETED, definitionPO.getDefinitionNm());
    }

    /**
     * 非结束节点同意审批
     *
     * @param requestDTO
     * @param definitionPO
     * @param data
     * @param instancePO
     * @param operationTime
     * @param currentNodeId
     * @param userId
     * @param multiType
     * @param sort
     */
    private void approved(WorkflowCommitDTO requestDTO, DefinitionPO definitionPO, Object data,
                          InstancePO instancePO, String operationTime, String currentNodeId,
                          String userId, String multiType, BigDecimal sort) {
        //执行流程过程业务逻辑
        WorkflowProcessHandler processHandler = getProcessHandler(definitionPO.getBusinessClass());
        if (processHandler != null) {
            WorkFlowProcessDTO workFlowProcessDTO = new WorkFlowProcessDTO();
            workFlowProcessDTO.setData(data);
            workFlowProcessDTO.setInstanceId(instancePO.getId());
            processHandler.approveMiddleProcess(workFlowProcessDTO);
        }
        //作废节点非当前节点任务
        cancelTask(operationTime, instancePO.getId(), currentNodeId, userId);
        //创建下个流程任务实例
        List<TaskInstancePO> nextTaskInstancePOS = saveTaskInstance(requestDTO.getAssigneeIds(), instancePO.getId(), requestDTO.getNextNodeId(),
                currentNodeId, multiType, sort.add(BigDecimal.ONE), CommonConstant.APPROVE_TYPE,null);
        //更新流程实例
        instancePO.setCurrentNodeId(requestDTO.getNextNodeId());
        instanceService.updateById(instancePO);
        //发送待办消息)
        messageService.sendTodoMessage(instancePO.getId(), nextTaskInstancePOS, definitionPO.getDefinitionNm());
    }

    /**
     * 作废节点任务实例
     *
     * @param operationTime
     * @param instanceId
     * @param currentNodeId
     * @param userId
     */
    private void cancelTask(String operationTime, String instanceId, String currentNodeId, String userId) {
        taskInstanceService.update(new LambdaUpdateWrapper<TaskInstancePO>()
                .set(TaskInstancePO::getStatus, CommonConstant.CANCELED)
                .set(TaskInstancePO::getOperationTime, operationTime)
                .eq(TaskInstancePO::getInstanceId, instanceId)
                .eq(TaskInstancePO::getCurrentNodeId, currentNodeId)
                .eq(TaskInstancePO::getStatus, CommonConstant.PENDING)
                .ne(TaskInstancePO::getAssigneeId, userId));
    }

    /**
     * 保存实例任务
     *
     * @param assigneeIds
     * @param instanceId
     * @param currentNodeId
     * @param previousNodeId
     */
    private List<TaskInstancePO> saveTaskInstance(List<String> assigneeIds, String instanceId, String currentNodeId,
                                                  String previousNodeId, String multiType, BigDecimal taskSort, String taskType, String taskId) {
        if (CollectionUtils.isEmpty(assigneeIds)) {
            throw new CustomException("流程处理人不能为空！");
        }
        List<TaskInstancePO> taskInstancePOS = new ArrayList<>();
        assigneeIds.forEach(assigneeId -> {
            TaskInstancePO taskInstancePO = new TaskInstancePO();
            taskInstancePO.setInstanceId(instanceId);
            taskInstancePO.setStatus(CommonConstant.PENDING);
            taskInstancePO.setCurrentNodeId(currentNodeId);
            taskInstancePO.setAssigneeId(assigneeId);
            taskInstancePO.setPreviousNodeId(previousNodeId);
            taskInstancePO.setMultiType(multiType);
            taskInstancePO.setSort(taskSort);
            taskInstancePO.setTaskType(taskType);
            taskInstancePO.setRelateTaskId(taskId);
            taskInstancePOS.add(taskInstancePO);
        });
        taskInstanceService.saveBatch(taskInstancePOS);
        return taskInstancePOS;
    }

    /**
     * 抄送
     *
     * @param ccToIds
     * @param InstanceId
     * @param taskId
     * @param ccTime
     */
    private void cc(List<String> ccToIds, String InstanceId, String taskId, String ccTime) {
        List<TaskCcPO> taskCcPOS = new ArrayList<>();
        for (String ccToID : ccToIds) {
            TaskCcPO taskCcPO = new TaskCcPO();
            taskCcPO.setInstanceId(InstanceId);
            if (StringUtils.isNotBlank(taskId)) {
                taskCcPO.setTaskInstanceId(taskId);
            }
            taskCcPO.setCcTime(ccTime);
            taskCcPO.setCcToId(ccToID);
            taskCcPOS.add(taskCcPO);
        }
        taskCcService.saveBatch(taskCcPOS);
    }

    /**
     * 获取流程过程业务处理器
     *
     * @param businessClass
     * @return
     */
    private WorkflowProcessHandler getProcessHandler(String businessClass) {
        //业务类不为空执行流程过程业务逻辑
        if (StringUtils.isNotBlank(businessClass)) {
            Class<?> aClass;
            try {
                aClass = Class.forName(businessClass);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            Object workflowProcessHandler = SpringContextUtils.getBean(aClass);
            if (workflowProcessHandler instanceof WorkflowProcessHandler) {
                return (WorkflowProcessHandler) workflowProcessHandler;
            }
        }
        return null;
    }


    @Transactional
    @Override
    public void revoke(WorkflowRevokeDTO requestDTO) {
        InstancePO instancePO = instanceService.getById(requestDTO.getInstanceId());
        if (instancePO == null) {
            throw new CustomException("流程实例不存在！");
        }
        if (CommonConstant.REJECTED.equals(instancePO.getStatus()) || CommonConstant.BACK.equals(instancePO.getStatus())) {
            throw new CustomException("非[拒绝]/[退回]状态不能重新发起流程！");
        }
        String operationTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        //更新未处理的流程任务实例为已撤销
        taskInstanceService.update(new LambdaUpdateWrapper<TaskInstancePO>()
                .set(TaskInstancePO::getStatus, CommonConstant.REVOKED)
                .set(TaskInstancePO::getOperationTime, operationTime)
                .eq(TaskInstancePO::getInstanceId, requestDTO.getInstanceId())
                .eq(TaskInstancePO::getStatus, CommonConstant.PENDING));
        //更新实例状态为已撤销
        instancePO.setStatus(CommonConstant.REVOKED);
        instancePO.setEndTime(operationTime);
        instanceService.updateById(instancePO);
    }

    @Override
    public List<BusinessFieldVO> dataDetail(WorkflowDataDetailDTO requestDTO) {
        //查询流程业务字段配置
        InstancePO instancePO = instanceService.getById(requestDTO.getInstanceId());
        if (instancePO == null) {
            throw new CustomException("流程实例不存在！");
        }
        List<BusinessFieldVO> businessFieldVOS = businessFieldService.getFields(instancePO.getDefinitionId());
        //获取实例的业务数据
        JSONObject data = (JSONObject) businessDataService.getData(requestDTO.getInstanceId());
        businessFieldVOS.forEach(item -> {
            if (data != null) {
                Object value = data.get(item.getFieldEnNm());
                item.setValue(value);
            }
        });
        return businessFieldVOS;
    }
}
